package cn.actoncode.boot.framework.common.util.crawler;

import cn.actoncode.boot.framework.common.enums.CrawlerSourceEnum;
import cn.actoncode.boot.framework.common.exception.ServiceException;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import static cn.actoncode.boot.framework.common.exception.enums.GlobalErrorCodeConstants.CUSTOMIZE_ERROR;
import static cn.actoncode.boot.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 文章爬取工具类
 *
 * @author bin
 */
@Slf4j
public class ArticleCrawlerUtil extends CrawlerUtil {
    
    /**
     * 根据文章链接抓取文章内容
     * 
     * @param url 文章链接
     * @return 文章内容
     */
    public static Article getArticle(String url, Integer crawlerSource) {
        CrawlerSourceEnum crawlerSourceEnum = CrawlerSourceEnum.valueOf(crawlerSource);
        if (null == crawlerSourceEnum) {
            throw exception(CUSTOMIZE_ERROR, "暂不支持该来源文章");
        }
        // 请求url获取html内容
        String html = getPageHtml(url);
        // 获取文章内容
        switch (crawlerSourceEnum) {
            case WP -> {
                return getWpArticleContent(html, url);
            }
            default -> throw exception(CUSTOMIZE_ERROR, "暂不支持该来源文章");
        }
    }
 
    /**
     * 检测是否支持链接
     */
    public static void checkUrl(String url, Integer source) {
        CrawlerSourceEnum crawlerSourceEnum = CrawlerSourceEnum.valueOf(source);
        if (url == null) {
            throw exception(CUSTOMIZE_ERROR, "请输入正确的链接");
        }
        if (!url.startsWith(crawlerSourceEnum.getDomain())) {
            throw exception(CUSTOMIZE_ERROR, crawlerSourceEnum.getExceptionMsg());
        }
    }
 
    
    /**
     * 解析微信公众号文章
     * 
     * @param url 文章链接
     * @return 文章信息
     */
    private static Article getWpArticleContent(String html, String url) {
        try {
            Document document = Jsoup.parse(html);

            Element videoElement = document.getElementById("js_video_page_title");
            if (null != videoElement) {
                throw exception(CUSTOMIZE_ERROR, "暂不支持视频解析");
            }
            Element imgElement = document.getElementById("js_image_content");
            if (null != imgElement) {
                throw exception(CUSTOMIZE_ERROR, "暂不支持图文解析");
            }

            // 文章出处（作者）
            String author = document.getElementsByClass("profile_nickname").get(0).text();
            // 文章封面图链接
            String coverUrl = document.select("meta[property=\"og:image\"]").get(0).attr("content");
            // 文章标题
            String title = document.getElementById("activity-name").text();
            // 文章内容
            Elements contentList = document.getElementsByClass("rich_media_content");
            StringBuilder contentSb = new StringBuilder();
            for (Element element : contentList) {
                getChildTag(element, contentSb);
            }
            String content = contentSb.toString();
            if (StrUtil.isEmpty(content)) {
                throw exception(CUSTOMIZE_ERROR, "文章解析失败");
            }
            return Article.builder().url(url).author(author).coverUrl(coverUrl).title(title).content(content).build();
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            log.info(e.getMessage());
            log.info("Get MP Article Error：{}", html);
            throw exception(CUSTOMIZE_ERROR, "文章解析失败");
        }
    }

    private static void getChildTag(Element element, StringBuilder contentSb) {
        String tagName = element.tagName();
        switch (tagName) {
            case "span", "p", "strong", "section" -> {
                Elements noscriptTags = element.select("noscript");
                if (CollUtil.isEmpty(noscriptTags)) {
                    contentSb.append(element.text());
                }
            }
            case "br" -> contentSb.append("\n");
            default -> {
                Elements childrenList = element.children();
                if (!childrenList.isEmpty()) {
                    for (Element element1 : childrenList) {
                        getChildTag(element1, contentSb);
                    }
                }
            }
        }
    }
}